package com.aos.service.user.impl;

import com.aos.client.AuthServiceClient;
import com.aos.dao.*;
import com.aos.dto.PermissionDto;
import com.aos.dto.PermissionsViewDto;
import com.aos.dto.RoleDto;
import com.aos.dto.UserDto;
import com.aos.dto.parameters.SynchroUserParameter;
import com.aos.dto.parameters.UserParameter;
import com.aos.dto.parameters.UserRegisterParameter;
import com.aos.entity.Application;
import com.aos.entity.UserRole;
import com.aos.entity.User;
import com.aos.properties.APMSProperties;
import com.aos.service.user.UserService;
import com.aos.util.*;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName UserServiceImpl
 * @Description:用户业务
 * @Author wumingwang
 * @Date 2018/9/7 16:09
 * @Version 1.0
 */
@Slf4j
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

    @Autowired
    private APMSProperties apmsProperties;

    @Autowired
    private UserRoleDao userRoleDao;

    @Autowired
    private RoleDao roleDao;

    @Autowired
    private PermissionDao permissionDao;

    @Autowired
    private ApplicationDao applicationDao;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private AuthServiceClient authServiceClient;

    @Override
    public Result queryByPage(Map<String, Object> map) {
        /**开启分页查询，sql的执行要紧跟这个分页工具*/
        PageHelper.startPage((int)map.get("pageNum"),(int)map.get("pageSize"));
        List<UserDto> list = userDao.queryByPage(map);
        PageInfo<UserDto> p = new PageInfo<>(list);
        return Result.ok(p);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result addUser(UserParameter appuser) {
        /**查询应用*/
        Application app = applicationDao.queryByCode(appuser.getAppCode());
        if(app == null){
            return Result.error("应用不存在，无法创建用户");
        }
        User user = new User();
        try{
            CopyUtils.copy(appuser,user);
        }catch (Exception e){
            log.error("属性复制错误！",e);
            return Result.error("系统繁忙，请稍后再试！");
        }
        user.setApplicationId(app.getId());
        if(userDao.queryForCheckByName(user) != null){
            return Result.error("用户登录名已存在！");
        }
        if(StringUtils.isEmpty(user.getPassword())){
            user.setPassword(apmsProperties.getUser().getDefaultPassword());
        }
        String password = user.getPassword();
        if(user.getParentId() == null){
            User parentUser = userDao.queryParentByAppId(app.getId());
            if(parentUser != null){
                user.setParentId(parentUser.getId());
            }else{
                user.setParentId(0L);
            }
        }
        user.setSalt(MD5Utils.getSalt());
        user.setCreatedTimestamp(new Date());
        user.setUpdatedDatetime(user.getCreatedTimestamp());
        user.setPassword(MD5Utils.degestMd5(user.getPassword(),user.getSalt()));
        userDao.insert(user);
        /**保存用户角色关系*/
        for(Map<Long,Long[]> rolemap : appuser.getRoles()){
            for (Long[] roles : rolemap.values()) {
                for(Long rid : roles){
                    UserRole userRole = new UserRole();
                    userRole.setUserId(user.getId());
                    userRole.setRoleId(rid);
                    userRoleDao.insert(userRole);
                }
            }
        }
        /**同步用户数据到授权中心(UAA)*/
        authServiceClient.data(user.getUsername(),user.getName(),password,app.getCode()
                ,apmsProperties.getUser().getDataInsert(),apmsProperties.getUser().getLoginType(),user.getId()
                ,user.getSalt());
        return Result.ok();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result deleteById(Long id) {
        userDao.delete(id);
        return Result.ok();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result updateUser(UserParameter appuser) {
        /**查询应用*/
        Application app = applicationDao.queryByCode(appuser.getAppCode());
        if(app == null){
            return Result.error("应用不存在，无法更新用户");
        }
        User user = new User();
        try{
            CopyUtils.copy(appuser,user);
        }catch (Exception e){
            log.error("属性复制错误！",e);
            return Result.error("系统繁忙，请稍后再试！");
        }
        User olduser = userDao.queryById(appuser.getId());
        if(olduser == null){
            return Result.error("要更新的用户不存在！");
        }
        if(userDao.queryForCheckByName(user) != null){
            return Result.error("用户登录名已存在！");
        }
        if(StringUtils.isEmpty(user.getPassword())){
            user.setPassword(null);
        }
        String username = olduser.getUsername();
        String name = olduser.getName();
        try{
            CopyUtils.copy(user,olduser);
        }catch (Exception e){
            log.error("属性复制错误！",e);
            return Result.error("系统繁忙，请稍后再试！");
        }
        olduser.setUpdatedDatetime(new Date());
        if(!StringUtils.isEmpty(user.getPassword())){
            olduser.setPassword(MD5Utils.degestMd5(user.getPassword(),olduser.getSalt()));
        }
        if(user.getParentId() == null){
            User parentUser = userDao.queryParentByAppId(app.getId());
            if(parentUser != null){
                olduser.setParentId(parentUser.getId());
            }else{
                olduser.setParentId(0L);
            }
        }
        userDao.update(olduser);

        for(Map<Long,Long[]> rolemap : appuser.getRoles()){
            for (Map.Entry<Long, Long[]> entry : rolemap.entrySet()) {
                /**删除该应用下用户原有角色*/
                userRoleDao.deleteByAppUser(olduser.getId(),entry.getKey());
                /**保存用户新角色*/
                for(Long rid : entry.getValue()){
                    UserRole userRole = new UserRole();
                    userRole.setUserId(user.getId());
                    userRole.setRoleId(rid);
                    userRoleDao.insert(userRole);
                }
            }
        }
        if(!username.equals(user.getUsername())
                || !StringUtils.isEmpty(user.getPassword())
                || !name.equals(user.getName())){
            /**同步更新用户数据到授权中心(UAA)*/
            authServiceClient.data(olduser.getUsername(),olduser.getName(),user.getPassword(),app.getCode()
                    ,apmsProperties.getUser().getDataUpdate(),apmsProperties.getUser().getLoginType(),olduser.getId()
                    ,olduser.getSalt());
        }
        return Result.ok();
    }

    @Override
    public Result queryDetails(Long id) {
        Map<String,Object> map = new HashMap<>();
        UserDto userDto = userDao.queryDetailsById(id);
        if(userDto == null ){
            return Result.error("用户不存在！");
        }
        /**返回前端隐藏密码*/
        userDto.setPassword(null);
        map.put("user",userDto);
        map.put("roleList",roleDao.queryRolesByAppAndUser(id,userDto.getApplicationId()));
        return Result.ok(map);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result frozenThawing(Long userId,String state) {
        User user = new User();
        user.setId(userId);
        user.setState(state);
        user.setUpdatedDatetime(new Date());
        userDao.updateState(user);
        String token = UserUtils.getToken();
        /**注销UAA*/
        authServiceClient.logout(token);
        /**删除缓存*/
        redisUtils.remove(token+apmsProperties.getUser().getRedisKey(),token+apmsProperties.getPermission().getRedisKey());
        return Result.ok();
    }

    /***
     * TODO 暂未加入授权的权限
     */
    @Override
    public Result getPermissionsByAppAndUser(Map<String, Object> map) {
        User user  = userDao.queryById((Long)map.get("userId"));
        if(user == null ){
            return Result.error("该用户不存在，请核查！");
        }
        if(apmsProperties.getUser().getStateDelete().equals(user.getState())){
            return Result.error("您的账户已注销，请联系管理员！");
        }
        if(apmsProperties.getUser().getStateOff().equals(user.getState())){
            return Result.error("该用户已冻结！");
        }
        Application app = applicationDao.queryById(user.getApplicationId());
        if(app == null){
            return Result.error("该用户所属应用不存在！");
        }
        if(apmsProperties.getApplication().getStateOff().equals(app.getState())){
            return Result.error("该用户所属应用已关闭！");
        }
        Map<String, Object> resmap = new HashMap<>();
        resmap.put("user",user);
        resmap.put("roles",roleDao.queryListByAppUserId(user.getId()));
        resmap.put("permissions",permissionDao.queryByAppUserId(user.getId(),app.getCode()));
        return Result.ok(resmap);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result userLogin(String userName, String password, String appCode) {
        UserDto userDto = userDao.checkForLogin(userName);
        if(userDto == null){
            return Result.error("账号或密码错误！");
        }
        /**更新最后登录时间*/
        userDto.setLastloginDatetime(new Date());
        userDao.update(userDto);
        if(!MD5Utils.degestMd5(password,userDto.getSalt()).equals(userDto.getPassword())){
            return Result.error("账号或密码错误！");
        }
        Application app = applicationDao.queryByCode(appCode);
        if(app == null){
            return Result.error("该应用不存在或未注册！");
        }
        if(apmsProperties.getUser().getStateDelete().equals(userDto.getState())){
            return Result.error("您的账户已注销，请联系管理员！");
        }
        if(apmsProperties.getUser().getStateOff().equals(userDto.getState())){
            return Result.error("您的账户已冻结，请联系管理员！");
        }
        if(apmsProperties.getApplication().getStateOff().equals(app.getState())){
            return Result.error("系统已暂停使用，请联系管理员！");
        }
        userDto.setAppCode(appCode);
        userDto.setAppSate(app.getState());
        return Result.ok(userDto);
    }

    @Override
    public Result operationUser(Result result, String accessToken) {
        UserDto userDto = (UserDto)result.getData();
        /**缓存用户信息*/
        redisUtils.set(accessToken+apmsProperties.getUser().getRedisKey(),userDto,apmsProperties.getCommon().getUserCacheSeconds(),TimeUnit.SECONDS);
        /**返回当前应用前端资源菜单资源*/
        List<PermissionDto> permissions = permissionDao.queryByAppUserId(userDto.getId(),userDto.getAppCode());
        /**缓存登录用户所有应用的权限url集合，数据格式：appcode-url*/
        Set<String> permissionUrls = permissionDao.queryPermissionUrls(userDto.getId());
        redisUtils.addSet(accessToken+apmsProperties.getPermission().getRedisKey(),permissionUrls,apmsProperties.getCommon().getUserCacheSeconds(),TimeUnit.SECONDS);
//        List<RoleDto> roles = roleDao.queryListByAppUserId(userDto.getId());
        List<RoleDto> roles = roleDao.queryListByAppCodeUserId(userDto.getId(),userDto.getAppCode());
        Set<String> rolename = new HashSet<>();
        if(!CollectionUtils.isEmpty(roles)){
            for(RoleDto rd : roles){
                rolename.add(rd.getRoleName());
            }
        }
        Map<String,Object> map = new HashMap<>();
        map.put("token",accessToken);
        map.put("permissions",buildPermissions(permissions));
        map.put("rolename",rolename);
        return Result.ok(map);
    }

    private Map<String,PermissionsViewDto> buildPermissions(List<PermissionDto> permissions){
        Map<String,PermissionsViewDto> map = new HashMap<>();
        if(CollectionUtils.isEmpty(permissions)){
            return map;
        }
        for(PermissionDto pd : permissions){
            if(pd.getPermissionType().equals("2")){
                /**菜单*/
                PermissionsViewDto view = new PermissionsViewDto();
                view.setIcon(pd.getIcon());
                view.setName(pd.getName());
                view.setSeq(pd.getSequence());
                view.setUrl(pd.getUrl());
                Set<String> button = new HashSet<>();
                for(PermissionDto pdo : permissions){
                    if(pd.getId().equals(pdo.getParentId())){
                        button.add(pdo.getCode());
                    }
                }
                view.setButton(button);
                map.put(pd.getCode(),view);
            }
        }
        return map;
    }

    @Override
    public Result logout() {
        String token = UserUtils.getToken();
        /**注销UAA*/
        authServiceClient.logout(token);
        /**删除缓存*/
        redisUtils.remove(token+apmsProperties.getUser().getRedisKey(),token+apmsProperties.getPermission().getRedisKey());
        return Result.ok();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result registerUser(UserRegisterParameter userRegister) {
        /**查询应用*/
        Application app = applicationDao.queryByCode(userRegister.getAppCode());
        if(app == null){
            return Result.error("应用不存在，无法注册用户");
        }
        User user = new User();
        try{
            CopyUtils.copy(userRegister,user);
        }catch (Exception e){
            log.error("属性复制错误！",e);
            return Result.error("系统繁忙，请稍后再试！");
        }
        if(userDao.queryForCheckByName(user) != null){
            return Result.error("用户登录名已存在！");
        }
        if(StringUtils.isEmpty(user.getPassword())){
            user.setPassword(apmsProperties.getUser().getDefaultPassword());
        }
        String password = user.getPassword();
        if(user.getParentId() == null){
            User parentUser = userDao.queryParentByAppId(app.getId());
            if(parentUser != null){
                user.setParentId(parentUser.getId());
            }else{
                user.setParentId(0L);
            }
        }
        user.setState(apmsProperties.getUser().getStateOn());
        user.setSalt(MD5Utils.getSalt());
        user.setApplicationId(app.getId());
        user.setCreatedTimestamp(new Date());
        user.setUpdatedDatetime(user.getCreatedTimestamp());
        user.setPassword(MD5Utils.degestMd5(user.getPassword(),user.getSalt()));
        userDao.insert(user);
        /**同步用户数据到授权中心(UAA)*/
        authServiceClient.data(user.getUsername(),user.getName(),password,app.getCode()
                ,apmsProperties.getUser().getDataInsert(),apmsProperties.getUser().getLoginType(),user.getId()
                ,user.getSalt());
        return Result.ok();
    }

    @Override
    public Result authentication(String token, String permission,String appCode) {
        token = token.replace("Bearer","");
        Set<?> permissionUrls = redisUtils.membersSet(token.trim()+apmsProperties.getPermission().getRedisKey());
        if(CollectionUtils.isEmpty(permissionUrls)){
            return Result.error("无权访问");
        }
        if(permissionUrls.contains(appCode+"-"+permission)){
            return Result.ok();
        }else{
            return Result.error("无权访问");
        }
    }

    @Override
    public Result getCurrentUser(String token) {
        return Result.ok(UserUtils.getCurrentUser(token.replace("Bearer","").trim()+apmsProperties.getUser().getRedisKey()));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result updateState(Long id, String state) {
        User user = new User();
        user.setId(id);
        user.setState(state);
        user.setUpdatedDatetime(new Date());
        userDao.updateState(user);
        return Result.ok();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result synchroUser(SynchroUserParameter synchroUser) {
        /**查询应用*/
        Application app = applicationDao.queryByCode(synchroUser.getAppCode());
        if(app == null){
            return Result.error("应用不存在，无法同步用户数据");
        }
        if(synchroUser.getDataType().equals(apmsProperties.getCommon().getDataTypeInsert())){
            /**新增用户*/
            synchroInsertUser(synchroUser,app);
        }else if(synchroUser.getDataType().equals(apmsProperties.getCommon().getDataTypeUpdate())){
            /**更新用户*/
            synchroUpdateUser(synchroUser,app);
        }else if(synchroUser.getDataType().equals(apmsProperties.getCommon().getDataTypeDelete())){
            /**删除用户*/
            User user = new User();
            user.setUsername(synchroUser.getUsername());
            user = userDao.queryForCheckByName(user);
            if(user == null){
                return Result.error("用户不存在，请检查用户登录名");
            }
            User upuser = new User();
            upuser.setId(user.getId());
            upuser.setState(apmsProperties.getUser().getStateDelete());
            upuser.setUpdatedDatetime(new Date());
            userDao.updateState(upuser);
        }else{
            return Result.error("用户数据同步类型错误！类型只能是："+apmsProperties.getCommon().getDataTypeInsert()+","+
                    apmsProperties.getCommon().getDataTypeUpdate()+","+apmsProperties.getCommon().getDataTypeDelete()
                    +",而传入类型："+synchroUser.getDataType());
        }
        return Result.ok();
    }

    /**新增用户*/
    private Result synchroInsertUser(SynchroUserParameter synchroUser,Application app){
        User user = new User();
        try{
            CopyUtils.copy(synchroUser,user);
        }catch (Exception e){
            log.error("属性复制错误！",e);
            return Result.error("系统繁忙，请稍后再试！");
        }
        /**新增用户*/
        if(userDao.queryForCheckByName(user) != null){
            return Result.error("用户登录名已存在！");
        }
        if(StringUtils.isEmpty(user.getPassword())){
            user.setPassword(apmsProperties.getUser().getDefaultPassword());
        }
        User parentUser = new User();
        if(StringUtils.isEmpty(synchroUser.getParentUsername())){
            parentUser = userDao.queryParentByAppId(app.getId());
            if(parentUser != null){
                user.setParentId(parentUser.getId());
            }else{
                user.setParentId(0L);
            }
        }else{
            parentUser.setUsername(synchroUser.getParentUsername());
            parentUser = userDao.queryForCheckByName(parentUser);
            if(parentUser == null){
                return Result.error("父级账号不存在");
            }
            user.setParentId(parentUser.getId());
        }
        if(StringUtils.isEmpty(user.getState())){
            user.setState(apmsProperties.getUser().getStateOn());
        }
        user.setSalt(MD5Utils.getSalt());
        user.setApplicationId(app.getId());
        user.setCreatedTimestamp(new Date());
        user.setUpdatedDatetime(user.getCreatedTimestamp());
        user.setPassword(MD5Utils.degestMd5(user.getPassword(),user.getSalt()));
        userDao.insert(user);
        /**使用传入角色，没有传入角色时，使用父用户的角色*/
        if(synchroUser.getRoleIds() != null && synchroUser.getRoleIds().length > 0){
            for(Long roleId : synchroUser.getRoleIds()){
                UserRole userRole = new UserRole();
                userRole.setUserId(user.getId());
                userRole.setRoleId(roleId);
                userRoleDao.insert(userRole);
            }
        }else{
            if(parentUser != null){
                List<RoleDto> roles = roleDao.queryListByAppUserId(parentUser.getId());
                if(!CollectionUtils.isEmpty(roles)){
                    for(RoleDto rd : roles){
                        UserRole userRole = new UserRole();
                        userRole.setUserId(user.getId());
                        userRole.setRoleId(rd.getId());
                        userRoleDao.insert(userRole);
                    }
                }
            }
        }

        /**同步用户数据到授权中心(UAA)*/
        authServiceClient.data(user.getUsername(),user.getName(),synchroUser.getPassword(),app.getCode()
                ,apmsProperties.getUser().getDataInsert(),apmsProperties.getUser().getLoginType(),user.getId()
                ,user.getSalt());
        return Result.ok();
    }

    /**更新用户*/
    private Result synchroUpdateUser(SynchroUserParameter synchroUser,Application app){
        if(StringUtils.isEmpty(synchroUser.getOldUsername())){
            return Result.error("更新用户数据时，旧用户登录名不能为空");
        }
        User oldUser = new User();
        oldUser.setUsername(synchroUser.getOldUsername());
        oldUser = userDao.queryForCheckByName(oldUser);
        if(oldUser == null){
            return Result.error("用户不存在，请检查旧用户登录名");
        }
        String password = oldUser.getPassword();
        String state = oldUser.getState();
        String username = oldUser.getUsername();
        String name = oldUser.getName();
        try{
            CopyUtils.copy(synchroUser,oldUser);
        }catch (Exception e){
            log.error("属性复制错误！",e);
            return Result.error("系统繁忙，请稍后再试！");
        }
        if(userDao.queryForCheckByName(oldUser) != null){
            return Result.error("新用户登录名已存在！");
        }
        if(synchroUser.getParentUsername() != null && synchroUser.getParentUsername().equals("")){
            User parentUser = userDao.queryParentByAppId(app.getId());
            if(parentUser != null){
                oldUser.setParentId(parentUser.getId());
            }else{
                oldUser.setParentId(0L);
            }
        }else if(!StringUtils.isEmpty(synchroUser.getParentUsername())){
            User parentUser = new User();
            parentUser.setUsername(synchroUser.getParentUsername());
            parentUser = userDao.queryForCheckByName(parentUser);
            if(parentUser == null){
                return Result.error("父级账号不存在");
            }
            oldUser.setParentId(parentUser.getId());
        }

        if(!StringUtils.isEmpty(synchroUser.getPassword())){
            oldUser.setPassword(MD5Utils.degestMd5(synchroUser.getPassword(),oldUser.getSalt()));
        }else{
            oldUser.setPassword(password);
        }
        if(StringUtils.isEmpty(synchroUser.getState())){
            oldUser.setState(state);
        }
        oldUser.setUpdatedDatetime(new Date());
        userDao.update(oldUser);
        if(!username.equals(synchroUser.getUsername())
                || !StringUtils.isEmpty(synchroUser.getPassword())
                || !name.equals(synchroUser.getName())){
            /**同步更新用户数据到授权中心(UAA)*/
            authServiceClient.data(oldUser.getUsername(),oldUser.getName(),synchroUser.getPassword(),app.getCode()
                    ,apmsProperties.getUser().getDataUpdate(),apmsProperties.getUser().getLoginType(),oldUser.getId()
                    ,oldUser.getSalt());
        }
        return Result.ok();
    }
}
